<template>
  <div>
    <el-table
      ref="table"
      v-loading="loading"
      :height="attrs.height || height"
      :data="tableData"
      size="medium"
      v-bind="attrs"
      element-loading-text="查询数据中"
      @current-change="onCurrentRowChange"
      @select-all="onSelectAllChange"
      @select="onSelectChange"
      @selection-change="onSelectionChange"
    >
      <slot></slot>
    </el-table>
    <div
      class="footer"
      :style="{
        margin: pagination.position == 'right' ? '8px -20px 8px 0px' : '8px 0px 8px -6px',
        float: pagination.position,
        flexDirection: pagination.position == 'right' ? 'row' : 'row-reverse'
      }"
    >
      <div v-if="timingEnabled" class="timing-info">
        <span>查询时间:</span>
        <span class="time">{{queryTime}}</span>
        <span>秒</span>
      </div>
      <el-pagination
        v-if="showPagination"
        :current-page="currentPage"
        :total="total"
        :page-sizes="pagination.pageSizes"
        :page-size="pagination.pageSize"
        :pager-count="pagination.pagerCount"
        :background="pagination.background"
        :layout="pagination.layout"
        @size-change="onSizeChange"
        @current-change="onCurrentChange"
      />
    </div>
  </div>
</template>


<script>
import config from '@/config/app.config';

export default {
  name: 'data-table',
  inheritAttrs: false,
  props: {
    url: {
      type: String
    },
    showPagination: {
      type: Boolean,
      default: true
    },
    showTotalOnly: {
      type: Boolean,
      default: false
    },
    queryParams: {
      type: Object
    },
    data: {
      type: [Array, null],
      default: () => null
    },
    loadFilter: {
      type: Function
    },
    lazy: {
      type: Boolean
    },
    timing: {
      type: Boolean,
      default: false
    }
  },
  data() {
    const cfg = config.get('datatable');
    const pagination = cfg.pagination;
    let pageSizes = [5, 8, 10, 15, 20, 30, 50];
    const index = pageSizes.findIndex(n => n > pagination.pageSize);
    pageSizes.splice(index > -1 ? index : pageSizes.length, 0, pagination.pageSize);

    return {
      fetchParams: this.queryParams,
      pagination: {
        pageSizes,
        pageSize: pagination.pageSize,
        pagerCount: pagination.pagerCount,
        background: pagination.background,
        layout: this.showTotalOnly ? 'total' : pagination.layout.join(','),
        position: pagination.position,
        ...this.$attrs.pagination
      },
      height: 0,
      currentPage: 1,
      currentRow: null,
      total: 0,
      tableData: [],
      loading: false,
      
      timingEnabled: !this.timing ? config.get('datatable').timingForce : this.timing,
      queryTime: 0
    };
  },
  beforeCreate() {
    const defaults = {
      stripe: config.get('datatable').stripe
    };
    this.attrs = Object.assign({}, defaults, this.$attrs);
  },
  watch: {
    data() {
      this._fetch();
    }
  },
  mounted() {
    if (!this.lazy) {
      this._fetch();
    }
  },
  methods: {
    onSizeChange(num) {
      this.pagination.pageSize = num;
      this._fetch();
    },
    onCurrentChange(num) {
      this.currentPage = num;
      this._fetch();
    },
    query(params) {
      // 如果传递了 查询参数，则覆盖上次的
      if (typeof params == 'object') {
        this.fetchParams = params;
      }
      this.currentPage = 1;
      return new Promise((solve, reject) => {
        this._fetch(solve, reject);
      });
    },
    clear() {
      this.loading = false;
      this.currentPage = 1;
      this.tableData = [];
    },
    reloadCurrentPage() {
      this._fetch();
    },
    async _fetch(solve, reject) {
      let params = {
        ...this.fetchParams,
      };
      if (this.showPagination) {
        params = {...params, ...{rows: this.pagination.pageSize, page: this.currentPage}};
      }

      if (!this.loading) {
        this.loading = true;
      }
      this.$emit('loading', true);
      let startTime = +new Date(); //记录请求开始时间
      if (this.timingEnabled) {
        this.startTimingAnimation();
      }
      let ret;
      if (this.url) {
        ret = await this.$http.get(this.url, {params}).catch(() => {
          reject && reject();
          if (this.timingEnabled) {
            this.stopTimingAnimation(0);
          }
        });
      } else {
        ret = this.data;
      }
      const diffTime = +new Date - startTime;
      if (this.timingEnabled) {
        this.stopTimingAnimation();
      }
      this.$emit('loading', false);
      if (!ret) {
        reject && reject();
        return;
      }
      // 加载数据，并让用户感知到执行了查询，在小于MIN_TIME毫秒之内，有相同的时长感觉
      const MIN_TIME = 100;
      const renderData = () => {
        if (this.loadFilter) {
          ret = this.loadFilter(ret);
        }
        this.tableData = ret.rows || ret;
        this.total = ret.total || ret.length;
        this.loading = false;
        solve && solve();
      };
      if (diffTime < MIN_TIME) {
        setTimeout(renderData, MIN_TIME - diffTime);
      } else {
        renderData();
      }
    },
    setCurrentRow(row) {
      this.$refs.table.setCurrentRow(row);
    },
    onCurrentRowChange(row) {
      this.currentRow = row;
    },
    onSelectAllChange(selections) {
      this.$emit('select-all', selections);
    },
    onSelectChange(selection, row) {
      this.$emit('select', selection, row);
    },
    onSelectionChange(selections) {
      this.$emit('selection-change', selections);
    },
    toggleRowSelection(row, selected) {
      this.$refs.table.toggleRowSelection(row, selected);
    },
    clearSelection() {
      this.$refs.table.clearSelection();
    },

    startTimingAnimation() {
      let _this = this;
      let startTime = 0;
      this.queryTime = 0;
      update();
      function update() {
        _this.timingAnimation = requestAnimationFrame((now) => {
          if (!startTime) startTime = now;
          _this.queryTime = ((now - startTime) / 1000).toFixed(3);
          _this.timingAnimation = requestAnimationFrame(update);
        });
      }
    },
    stopTimingAnimation(time) {
      cancelAnimationFrame(this.timingAnimation);
      if (time) {
        this.queryTime = time;
      }
    }
  }
}
</script>

<style scoped>
.footer {
  display: flex;
  height: 32px;
}

>>> .el-pagination__jump {
  margin: 0px 5px;
}
>>> .timing-info {
  display: inline-block;
  padding-right: 16px;
  font-size: 12px;
  color: #909399;
  line-height: 32px;
}
>>> .timing-info > .time {
  display: inline-block;
  transition: 1s opacity ease-in-out;
  min-width: 30px;
  opacity: 1;
}
>>> .timing-info > .time.loading {
  opacity: 0;
}
>>> .timing-info > .time:not(.loading) {
  opacity: 1;
}
</style>